/*
 * Copyright (c) 2020-2099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.amqp.rabbitmq;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.Ordered;
import org.tianyun.cloud.amqp.rabbitmq.autoconfigure.RabbitMqAutoConfiguration;
import org.tianyun.cloud.amqp.rabbitmq.refresh.RabbitContainerRefresher;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 通过@RabbitContainer注解来初始化RabbitMQ连接，配合RabbitContainerRegistrar使用，这一步用来移除springboot自动配置的bean，替换成自己的bean
 *
 * @auther ebert_chan
 */
public class RabbitMqContainerPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {

    private List<RabbitMqConnectionFactoryConfigurer> rabbitMqConnectionFactoryConfigurers;

    private int order = Ordered.LOWEST_PRECEDENCE - 101;

    public RabbitMqContainerPostProcessor(ObjectProvider<List<RabbitMqConnectionFactoryConfigurer>> rabbitMqConnectionFactoryConfigurerProvider) {
        this.rabbitMqConnectionFactoryConfigurers = rabbitMqConnectionFactoryConfigurerProvider.getIfAvailable();
    }

    /*
     * @see org.springframework.core.Ordered#getOrder()
     */
    @Override
    public int getOrder() {
        return this.order;
    }

    /*
     * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.
     * ConfigurableListableBeanFactory)
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

    /*
     * @see org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(org.springframework.beans.
     * factory.support.BeanDefinitionRegistry)
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        if (rabbitMqConnectionFactoryConfigurers == null || rabbitMqConnectionFactoryConfigurers.isEmpty()) {
            return;
        }

        if (registry.containsBeanDefinition(RabbitMqAutoConfiguration.RABBIT_CONNECTION_FACTORY_BEAN)) {
            registry.removeBeanDefinition(RabbitMqAutoConfiguration.RABBIT_CONNECTION_FACTORY_BEAN);
        }
        if (registry.containsBeanDefinition(RabbitMqAutoConfiguration.RABBIT_LISTENER_CONTAINER_FACTORY_BEAN)) {
            registry.removeBeanDefinition(RabbitMqAutoConfiguration.RABBIT_LISTENER_CONTAINER_FACTORY_BEAN);
        }
        if (registry.containsBeanDefinition(RabbitMqAutoConfiguration.RABBIT_TEMPLATE_BEAN)) {
            registry.removeBeanDefinition(RabbitMqAutoConfiguration.RABBIT_TEMPLATE_BEAN);
        }

        rabbitMqConnectionFactoryConfigurers.forEach(c -> c.registryBean(registry));

        List<RabbitContainerBeanWrapper> rabbitContainerBeanWrappers = rabbitMqConnectionFactoryConfigurers.stream()
                .map(RabbitMqConnectionFactoryConfigurer::getRabbitContainerBeanWrapper).collect(Collectors.toList());

        BeanDefinition rabbitContainerRefresherBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(RabbitContainerRefresher.class)
                .addConstructorArgValue(rabbitContainerBeanWrappers).getBeanDefinition();

        registry.registerBeanDefinition(RabbitContainerRefresher.class.getSimpleName(), rabbitContainerRefresherBeanDefinition);
    }

}
